package com.bt7274.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.bt7274.enums.PromotionType;
import com.bt7274.exception.BusinessException;
import com.bt7274.mapper.*;
import com.bt7274.pojo.*;
import com.bt7274.pojo.bo.PromotionBO;
import com.bt7274.pojo.bo.PromotionUpdateBO;
import com.bt7274.pojo.bo.UserParticipateBO;
import com.bt7274.pojo.vo.ActivityRecordVO;
import com.bt7274.pojo.vo.PromotionListVO;
import com.bt7274.pojo.vo.PromotionVO;
import com.bt7274.pojo.vo.UserPromotionVO;
import com.bt7274.service.PromotionPolicyService;
import com.bt7274.service.PromotionService;
import com.bt7274.utils.PageResponse;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PromotionServiceImpl implements PromotionService {

    private final PromotionMapper promotionMapper;
    private final ActivityRecordMapper activityRecordMapper;
    private final PromotionPolicyService promotionPolicyService;
    private final UserMapper userMapper;
    private final UserExpMapper userExpMapper;
    private final BtTransactionMapper btTransactionMapper;

    @Override
    @Transactional
    public String createPromotion(PromotionBO promotionBO) {
    // 验证时间
        if (promotionBO.getEndTime().isBefore(promotionBO.getStartTime())) {
            throw new BusinessException("结束时间不能早于开始时间");
        }

        // 验证促销类型是否有效
        PromotionType promotionType = PromotionType.getPromotionTypeByString(promotionBO.getType());

        // 验证促销类型是否对应有效的促销策略
        PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotionType.name().toLowerCase());
        if (policy == null) {
            // TODO:如果没有找到对应的策略，创建一个
            policy = createPromotionPolicyForType(promotionType);
        }

        // 检查是否有同类型的活动在时间上重叠
        if (hasOverlappingPromotion(promotionBO.getType(), promotionBO.getStartTime(),
                promotionBO.getEndTime(), null)) {
            throw new BusinessException("该时间段内已存在相同类型的活动");
        }

        Promotion promotion = new Promotion();
        BeanUtils.copyProperties(promotionBO, promotion);
        promotion.setType(promotionType.name());
        promotion.setId(UUID.randomUUID().toString().replace("-", ""));

        promotionMapper.insert(promotion);
        log.info("创建促销活动: {}, 类型: {}", promotion.getTitle(), promotion.getType());

        return promotion.getId();
    }

    @Override
    @Transactional
    public void updatePromotion(PromotionUpdateBO promotionUpdateBO) {
        Promotion existPromotion = promotionMapper.selectById(promotionUpdateBO.getId());
        if (existPromotion == null) {
            throw new BusinessException("活动不存在");
        }

        // 如果修改了类型，验证新类型是否有效
        if (StringUtils.hasText(promotionUpdateBO.getType())) {
            PromotionType promotionType = PromotionType.getPromotionTypeByString(promotionUpdateBO.getType());
            PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotionType.name().toLowerCase());

            if (policy == null) {
                policy = createPromotionPolicyForType(promotionType);
            }
            promotionUpdateBO.setType(promotionType.name());
        }

        Promotion promotion = new Promotion();
        BeanUtils.copyProperties(promotionUpdateBO, promotion);

        // 验证时间
        if (promotion.getEndTime() != null && promotion.getStartTime() != null
                && promotion.getEndTime().isBefore(promotion.getStartTime())) {
            throw new BusinessException("结束时间不能早于开始时间");
        }

        // 检查时间重叠
        String type = StringUtils.hasText(promotion.getType()) ?
                promotion.getType() : existPromotion.getType();
        if (hasOverlappingPromotion(type, promotion.getStartTime(), promotion.getEndTime(), promotion.getId())) {
            throw new BusinessException("该时间段内已存在相同类型的活动");
        }

        promotionMapper.updateById(promotion);
        log.info("更新促销活动: {}", promotion.getId());
    }


    @Override
    @Transactional
    public void deletePromotion(String id) {
        Promotion promotion = promotionMapper.selectById(id);
        if (promotion == null) {
            throw new BusinessException("活动不存在");
        }

        // 检查是否有用户参与记录
        QueryWrapper<ActivityRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("promotion_id", id);
        Long count = activityRecordMapper.selectCount(wrapper);

        if (count > 0) {
            throw new BusinessException("该活动已有" + count + "名用户参与，无法删除");
        }

        promotionMapper.deleteById(id);
        log.info("删除促销活动: {}", promotion.getId());
    }

    @Override
    public PromotionVO getPromotionById(String id) {
        Promotion promotion = promotionMapper.selectById(id);
        if (promotion == null) {
            throw new BusinessException("活动不存在");
        }

        PromotionVO promotionVO = new PromotionVO();
        BeanUtils.copyProperties(promotion, promotionVO);

        // 设置活动状态
        promotionVO.setStatus(getPromotionStatus(promotion));

        // 获取参与人数
        QueryWrapper<ActivityRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("promotion_id", id);
        Long participantCount = activityRecordMapper.selectCount(wrapper);
        promotionVO.setParticipantCount(participantCount);

        // 获取对应的促销策略信息
        PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotion.getType());
        if (policy != null) {
            promotionVO.setPolicyDisplayName(policy.getDisplayName());
            promotionVO.setUploadRatio(policy.getUploadRatio());
            promotionVO.setDownloadRatio(policy.getDownloadRatio());
        }

        return promotionVO;
    }

    @Override
    public PageResponse<PromotionListVO> getPromotionList(Integer current, Integer size, String type, Integer isActive) {
        Page<Promotion> page = new Page<>(current, size);
        QueryWrapper<Promotion> wrapper = new QueryWrapper<>();

        if (StringUtils.hasText(type)) {
            wrapper.eq("type", type);
        }
        if (isActive != null) {
            wrapper.eq("is_active", isActive);
        }

        wrapper.orderByDesc("start_time");

        IPage<Promotion> promotionPage = promotionMapper.selectPage(page, wrapper);

        List<PromotionListVO> promotionList = promotionPage.getRecords().stream()
                .map(this::convertToListVO)
                .collect(Collectors.toList());

        return new PageResponse<>(promotionList, promotionPage.getTotal(),
                promotionPage.getCurrent(), promotionPage.getSize());
    }


    @Override
    public List<PromotionListVO> getActivePromotions() {

        QueryWrapper<Promotion> wrapper = new QueryWrapper<>();
        wrapper.eq("is_active", 1);
        wrapper.le("start_time", LocalDateTime.now());
        wrapper.ge("end_time", LocalDateTime.now());
        wrapper.orderByDesc("start_time");

        List<Promotion> promotions = promotionMapper.selectList(wrapper);

        return promotions.stream()
                .map(this::convertToListVO)
                .collect(Collectors.toList());
    }

    @Override
    public void togglePromotionStatus(String promotionId, Integer isActive) {
        Promotion promotion = promotionMapper.selectById(promotionId);
        if (promotion == null) {
            throw new BusinessException("活动不存在");
        }

        promotion.setIsActive(isActive);
        promotionMapper.updateById(promotion);
        log.info("切换活动状态：: {}, 新状态: {}", promotion.getId(), isActive == 1 ? "激活" : "禁用");
    }

    @Override
    public PageResponse<ActivityRecordVO> getActivityRecords(String promotionId,
                                                             Integer current, Integer size) {
        Page<ActivityRecord> page = new Page<>(current, size);
        QueryWrapper<ActivityRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("promotion_id", promotionId);
        wrapper.orderByDesc("participated_time");

        IPage<ActivityRecord> recordPage = activityRecordMapper.selectPage(page, wrapper);

        List<ActivityRecordVO> records = recordPage.getRecords().stream()
                .map(this::convertToActivityRecordVO)
                .collect(Collectors.toList());

        return new PageResponse<>(records, recordPage.getTotal(),
                recordPage.getCurrent(), recordPage.getSize());
    }



    // ==========用户==============


    @Override
    public List<UserPromotionVO> getAvailablePromotions(String userId) {
        // 获取当前进行中的活动
        List<Promotion> activePromotions = getActivePromotionsList();

        // 过滤出用户未参加的活动
        List<UserPromotionVO> availablePromotions = new ArrayList<>();

        for (Promotion promotion : activePromotions) {
            if (!hasParticipated(userId, promotion.getId())) {
                UserPromotionVO vo = new UserPromotionVO();
                BeanUtils.copyProperties(promotion, vo);

                // 设置活动状态和促销策略信息
                vo.setStatus(getPromotionStatus(promotion));
                vo.setHasParticipated(false);

                PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotion.getType());
                if (policy != null) {
                    vo.setPolicyDisplayName(policy.getDisplayName());
                    vo.setUploadRatio(policy.getUploadRatio());
                    vo.setDownloadRatio(policy.getDownloadRatio());
                }

                availablePromotions.add(vo);
            }
        }

        return availablePromotions;
    }


    @Transactional
    public String participatePromotion(UserParticipateBO participateBO) {
        String userId = participateBO.getUserId();
        String promotionId = participateBO.getPromotionId();

        // 验证用户是否存在
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 验证活动是否存在且进行中
        Promotion promotion = promotionMapper.selectById(promotionId);
        if (promotion == null) {
            throw new BusinessException("活动不存在");
        }

        String status = getPromotionStatus(promotion);
        if (!"进行中".equals(status)) {
            throw new BusinessException("活动" + status + "，无法参加");
        }

        // 检查是否已参加
        if (hasParticipated(userId, promotionId)) {
            throw new BusinessException("您已参加过此活动");
        }

        // 根据活动类型和促销策略计算奖励
        PromotionType promotionType = PromotionType.getPromotionTypeByString(promotion.getType());
        PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotionType.name().toLowerCase());
        if (policy == null) {
            policy = createPromotionPolicyForType(promotionType);
        }

        // 计算和发放奖励
        String reward = calculateAndDistributeReward(user, promotion, policy, promotionType);

        // 创建参与记录
        ActivityRecord record = new ActivityRecord();
        record.setId(UUID.randomUUID().toString().replace("-", ""));
        record.setUserId(userId);
        record.setPromotionId(promotionId);
        record.setReward(reward);
        record.setParticipatedTime(LocalDateTime.now());

        activityRecordMapper.insert(record);

        log.info("用户 {} 参加活动 {}, 获得奖励: {}", userId, promotion.getTitle(), reward);

        return reward;
    }

    @Override
    public boolean hasParticipated(String userId, String promotionId) {
        QueryWrapper<ActivityRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("promotion_id", promotionId);
        return activityRecordMapper.selectCount(wrapper) > 0;
    }

    @Override
    public PageResponse<ActivityRecordVO> getUserActivityRecords(String userId,
                                                                 Integer current, Integer size) {
        Page<ActivityRecord> page = new Page<>(current, size);
        QueryWrapper<ActivityRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.orderByDesc("participated_time");

        IPage<ActivityRecord> recordPage = activityRecordMapper.selectPage(page, wrapper);

        List<ActivityRecordVO> records = recordPage.getRecords().stream()
                .map(this::convertToActivityRecordVO)
                .collect(Collectors.toList());

        return new PageResponse<>(records, recordPage.getTotal(),
                recordPage.getCurrent(), recordPage.getSize());
    }

//    @Override
//    @Transactional
//    public void applyPromotionToTorrent(Long torrentId, String promotionPolicySlug) {
//        Torrent torrent = torrentMapper.selectById(torrentId);
//        if (torrent == null) {
//            throw new BusinessException("种子不存在");
//        }
//
//        PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotionPolicySlug);
//        if (policy == null) {
//            throw new BusinessException("促销策略不存在");
//        }
//
//        torrent.setPromotionPolicyId(policy.getId());
//        torrentMapper.updateById(torrent);
//
//        log.info("为种子 {} 应用促销策略: {}", torrentId, promotionPolicySlug);
//    }

    @Override
    @Transactional
    public void applyPromotionToUser(String userId, Long promotionPolicyId) {
        UserExp userExp = userExpMapper.selectById(userId);
        if (userExp == null) {
            // 如果用户扩展信息不存在，创建一个
            userExp = new UserExp();
            userExp.setId(userId);
            userExp.setPromotionPolicyId(promotionPolicyId);
            userExp.setRatio(new BigDecimal("1.00"));
            userExp.setExperience(0);
            userExp.setBt(0);
            userExp.setUpdatedTime(LocalDateTime.now());
            userExpMapper.insert(userExp);
    } else {
        userExp.setPromotionPolicyId(promotionPolicyId);
        userExp.setUpdatedTime(LocalDateTime.now());
        userExpMapper.updateById(userExp);
    }

        PromotionPolicy policy = promotionPolicyService.getPromotionPolicyById(promotionPolicyId);


        log.info("为用户 {} 应用促销策略: {}", userId, policy.getSlug());
    }

    // ========== 辅助方法，私有 ==========

    /**
     * 检查是否有时间重叠的同类型活动
     */
    private boolean hasOverlappingPromotion(String type, LocalDateTime startTime,
                                            LocalDateTime endTime, String excludeId) {
        QueryWrapper<Promotion> wrapper = new QueryWrapper<>();
        wrapper.eq("type", type);
        wrapper.eq("is_active", 1);

        if (excludeId != null) {
            wrapper.ne("id", excludeId);
        }

        // 检查时间重叠：新活动的开始时间在已有活动期间，或新活动的结束时间在已有活动期间
        wrapper.and(w -> w
                .and(w1 -> w1.le("start_time", startTime).ge("end_time", startTime))
                .or(w2 -> w2.le("start_time", endTime).ge("end_time", endTime))
                .or(w3 -> w3.ge("start_time", startTime).le("end_time", endTime))
        );

        return promotionMapper.selectCount(wrapper) > 0;
    }

    /**
     * 获取活动状态
     */
    private String getPromotionStatus(Promotion promotion) {
        LocalDateTime now = LocalDateTime.now();

        if (promotion.getIsActive() == 0) {
            return "已禁用";
        }

        if (now.isBefore(promotion.getStartTime())) {
            return "未开始";
        } else if (now.isAfter(promotion.getEndTime())) {
            return "已结束";
        } else {
            return "进行中";
        }
    }

    /**
     * 获取进行中的活动列表
     */
    private List<Promotion> getActivePromotionsList() {
        QueryWrapper<Promotion> wrapper = new QueryWrapper<>();
        wrapper.eq("is_active", 1);
        wrapper.le("start_time", LocalDateTime.now());
        wrapper.ge("end_time", LocalDateTime.now());
        wrapper.orderByDesc("start_time");

        return promotionMapper.selectList(wrapper);
    }

    /**
     * 转换为列表VO
     */
    private PromotionListVO convertToListVO(Promotion promotion) {
        PromotionListVO listVO = new PromotionListVO();
        BeanUtils.copyProperties(promotion, listVO);

        // 设置活动状态
        listVO.setStatus(getPromotionStatus(promotion));

        // 获取参与人数
        QueryWrapper<ActivityRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("promotion_id", promotion.getId());
        Long participantCount = activityRecordMapper.selectCount(wrapper);
        listVO.setParticipantCount(participantCount);

        // 获取促销策略信息
        PromotionType promotionType = PromotionType.getPromotionTypeByString(promotion.getType());
        PromotionPolicy policy = promotionPolicyService.getPromotionPolicyBySlug(promotionType.name().toLowerCase());
        if (policy != null) {
            listVO.setPolicyDisplayName(policy.getDisplayName());
        } else {
            listVO.setPolicyDisplayName(promotionType.getDescription());
        }

        return listVO;
    }

    /**
     * 转换为活动记录VO
     */
    private ActivityRecordVO convertToActivityRecordVO(ActivityRecord record) {
        ActivityRecordVO vo = new ActivityRecordVO();
        BeanUtils.copyProperties(record, vo);

        // 获取用户信息
        User user = userMapper.selectById(record.getUserId());
        if (user != null) {
            vo.setUsername(user.getUsername());
        }

        // 获取活动信息
        Promotion promotion = promotionMapper.selectById(record.getPromotionId());
        if (promotion != null) {
            vo.setPromotionTitle(promotion.getTitle());
            vo.setPromotionType(promotion.getType());
        }

        return vo;
    }

    /**
     * 计算和发放奖励
     */
    private String calculateAndDistributeReward(User user, Promotion promotion, PromotionPolicy policy, PromotionType promotionType) {
        StringBuilder rewardBuilder = new StringBuilder();

            // 根据不同的促销类型计算奖励
            switch (promotionType) {
                case FREE:
                    // 免费活动 - 免费下载特权
                    applyPromotionToUser(user.getId(), policy.getId());
                    rewardBuilder.append("获得免费下载特权至活动结束");
                    break;

                case HALF_PRICE:
                    // 半价活动 - 下载消耗减半
                    applyPromotionToUser(user.getId(), policy.getId());
                    rewardBuilder.append("获得半价下载特权至活动结束（下载消耗减半）");
                    break;

                case DOUBLE_UPLOAD:
                    // 双倍上传活动
                    applyPromotionToUser(user.getId(), policy.getId());
                    rewardBuilder.append("获得双倍上传奖励至活动结束");
                    break;

                case DOUBLE_DOWNLOAD:
                    // 双倍下载消耗活动（0.5倍，即下载消耗减半）
                    applyPromotionToUser(user.getId(), policy.getId());
                    rewardBuilder.append("获得优惠下载特权至活动结束（下载消耗减半）");
                    break;

                case DOUBLE_UPLOAD_DOWNLOAD:
                    // 双倍上传 + 半价下载
                    applyPromotionToUser(user.getId(), policy.getId());
                    rewardBuilder.append("获得双倍上传奖励和半价下载特权至活动结束");
                    break;

                case NORMAL:
                default:
                    // 普通活动 - 只发放BT币奖励
                    int btReward = 20;
                    distributeBtCoins(user.getId(), btReward, "参加活动：" + promotion.getTitle());
                    rewardBuilder.append("获得 ").append(btReward).append(" BT币");
                    break;
            }

            return rewardBuilder.toString();
        }

    /**
     * 根据促销类型创建对应的促销策略
     */
    private PromotionPolicy createPromotionPolicyForType(PromotionType promotionType) {
        PromotionPolicy policy = new PromotionPolicy();
        policy.setSlug(promotionType.name().toLowerCase());
        policy.setDisplayName(promotionType.getDescription());

        // 根据促销类型设置上传/下载比例
        switch (promotionType) {
            case FREE:
                policy.setUploadRatio(1.0);
                policy.setDownloadRatio(0.0); // 免费下载
                break;
            case HALF_PRICE:
                policy.setUploadRatio(1.0);
                policy.setDownloadRatio(0.5); // 半价下载
                break;
            case DOUBLE_UPLOAD:
                policy.setUploadRatio(2.0); // 双倍上传
                policy.setDownloadRatio(1.0);
                break;
            case DOUBLE_DOWNLOAD:
                policy.setUploadRatio(1.0);
                policy.setDownloadRatio(0.5); // 0.5倍下载（即半价）
                break;
            case DOUBLE_UPLOAD_DOWNLOAD:
                policy.setUploadRatio(2.0); // 双倍上传
                policy.setDownloadRatio(0.5); // 半价下载
                break;
            case NORMAL:
            default:
                policy.setUploadRatio(1.0);
                policy.setDownloadRatio(1.0);
                break;
        }

        // 保存策略
        return promotionPolicyService.createPromotionPolicy(policy);
    }

    /**
     * 发放BT币
     */
    private void distributeBtCoins(String userId, int amount, String description) {
        // 更新用户BT币余额
        UserExp userExp = userExpMapper.selectById(userId);
        if (userExp == null) {
            userExp = new UserExp();
            userExp.setId(userId);
            userExp.setBt(amount);
            userExpMapper.insert(userExp);
        } else {
            userExp.setBt(userExp.getBt() + amount);
            userExpMapper.updateById(userExp);
        }
        BtTransaction transaction = new BtTransaction();
        transaction.setId(UUID.randomUUID().toString().replace("-", ""));
        transaction.setUserId(userId);
        transaction.setPoints(amount);
        transaction.setType("PROMOTION_REWARD");
        transaction.setRuleId("PROMOTION");
        transaction.setDescription(description);
        transaction.setCreatedTime(LocalDateTime.now());
        btTransactionMapper.insert(transaction);
    }

    /**
     * 临时应用促销策略（实际实现可能需要额外的表来记录临时促销）
     */
    private void applyTemporaryPromotionPolicy(String userId, Long policyId, LocalDateTime endTime) {
        // 这里简化处理，直接更新用户的促销策略
        // 实际应用中可能需要一个临时促销记录表来管理时效性
        UserExp userExp = userExpMapper.selectById(userId);
        if (userExp != null) {
            userExp.setPromotionPolicyId(policyId);
            userExpMapper.updateById(userExp);
        }

        // TODO: 可以创建一个定时任务，在活动结束时恢复用户的默认促销策略
    }

    /**
     * 判断是否为新用户（注册30天内）
     */
    private boolean isNewUser(User user) {
        return user.getCreatedTime().isAfter(LocalDateTime.now().minusDays(30));
    }

    /**
     * 判断是否为高等级用户（权限组 >= 5）
     */
    private boolean isVipUser(User user) {
        return user.getPermissionGroup() >= 5;
    }

}